package com.zuche.seraph.remoting.agent.util;

public class Base64 {

    private static final char[] lookup = new char[64];
    private static final byte[] reverseLookup = new byte[256];

    private Base64() {
    }

    public static String encode(byte[] bytes) {
        StringBuilder buf = new StringBuilder((bytes.length + 2) / 3 * 4);
        int i = 0;
        int len = bytes.length - 2;

        int chunk;
        while(i < len) {
            chunk = (bytes[i++] & 255) << 16 | (bytes[i++] & 255) << 8 | bytes[i++] & 255;
            buf.append(lookup[chunk >> 18]);
            buf.append(lookup[chunk >> 12 & 63]);
            buf.append(lookup[chunk >> 6 & 63]);
            buf.append(lookup[chunk & 63]);
        }

        len = bytes.length;
        if (i < len) {
            chunk = (bytes[i++] & 255) << 16;
            buf.append(lookup[chunk >> 18]);
            if (i < len) {
                chunk |= (bytes[i] & 255) << 8;
                buf.append(lookup[chunk >> 12 & 63]);
                buf.append(lookup[chunk >> 6 & 63]);
            } else {
                buf.append(lookup[chunk >> 12 & 63]);
                buf.append('=');
            }

            buf.append('=');
        }

        return buf.toString();
    }

    public static byte[] decode(String encoded) {
        int padding = 0;

        int length;
        for(length = encoded.length() - 1; encoded.charAt(length) == '='; --length) {
            ++padding;
        }

        length = encoded.length() * 6 / 8 - padding;
        byte[] bytes = new byte[length];
        int i = 0;
        int index = 0;

        for(int n = encoded.length(); i < n; i += 4) {
            int word = reverseLookup[encoded.charAt(i)] << 18;
            word += reverseLookup[encoded.charAt(i + 1)] << 12;
            word += reverseLookup[encoded.charAt(i + 2)] << 6;
            word += reverseLookup[encoded.charAt(i + 3)];

            for(int j = 0; j < 3 && index + j < length; ++j) {
                bytes[index + j] = (byte)(word >> 8 * (2 - j));
            }

            index += 3;
        }

        return bytes;
    }

    static {
        int i;
        for(i = 0; i < 26; ++i) {
            lookup[i] = (char)(65 + i);
        }

        i = 26;

        int j;
        for(j = 0; i < 52; ++j) {
            lookup[i] = (char)(97 + j);
            ++i;
        }

        i = 52;

        for(j = 0; i < 62; ++j) {
            lookup[i] = (char)(48 + j);
            ++i;
        }

        lookup[62] = '+';
        lookup[63] = '/';

        for(i = 0; i < 256; ++i) {
            reverseLookup[i] = -1;
        }

        for(i = 90; i >= 65; --i) {
            reverseLookup[i] = (byte)(i - 65);
        }

        for(i = 122; i >= 97; --i) {
            reverseLookup[i] = (byte)(i - 97 + 26);
        }

        for(i = 57; i >= 48; --i) {
            reverseLookup[i] = (byte)(i - 48 + 52);
        }

        reverseLookup[43] = 62;
        reverseLookup[47] = 63;
        reverseLookup[61] = 0;
    }
}
